//
//  JKJailbreakHelper.m
//  JKJailbreak
//
//  Created by 王冲 on 2019/4/9.
//  Copyright © 2019 JK科技有限公司. All rights reserved.
//

#import "JKJailbreakHelper.h"
#import "AppDelegate.h"
#import <sys/stat.h>
#import <dlfcn.h>
#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])

@implementation JKJailbreakHelper

char* printEnv(void) {
    char *env = getenv("DYLD_INSERT_LIBRARIES");
    return env;
}

const char* jailbreak_tool_pathes[] = {
    "/Applications/Cydia.app",
    "/Applications/limera1n.app",
    "/Applications/greenpois0n.app",
    "/Applications/blackra1n.app",
    "/Applications/blacksn0w.app",
    "/Applications/redsn0w.app",
    "/Applications/Absinthe.app",
    "/Library/MobileSubstrate/MobileSubstrate.dylib",
    "/bin/bash",
    "/usr/sbin/sshd",
    "/etc/apt",
    "/private/var/lib/apt/",
    NULL,
};

+(BOOL)isJailBreak{
    
    // 只要满足一种条件就是越狱了
    if ([self isJailBreak1] || [self isJailBreak2] || [self isJailBreak3] || [self isJailBreak4] || [self isJailBreak5] || [self isJailBreak6]) {
        return YES;
    }
    return NO;
}

#pragma mark 1.通过手机越狱后增加的越狱文件判断
/**
 通过手机越狱后增加的越狱文件判断,判断这些文件是否存在，只要有存在的，就可以认为手机已经越狱了。
 */
+(BOOL)isJailBreak1
{
    for (int i=0; i<ARRAY_SIZE(jailbreak_tool_pathes); i++) {
        if ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithUTF8String:jailbreak_tool_pathes[i]]]) {
            NSLog(@"The device is jail broken!");
            return YES;
        }
    }
    NSLog(@"The device is NOT jail broken!");
    return NO;
}


#pragma mark 2.根据是否能打开cydia判断
+(BOOL)isJailBreak2{
    
    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://"]]) {
        NSLog(@"The device is jail broken!");
        return YES;
    }
    NSLog(@"The device is NOT jail broken!");
    return NO;
}

#pragma mark 3.根据是否能获取所有应用的名称判断,没有越狱的设备是没有读取所有应用名称的权限的
+(BOOL)isJailBreak3{
    if ([[NSFileManager defaultManager] fileExistsAtPath:@"User/Applications/"]) {
        NSLog(@"The device is jail broken!");
        NSArray *appList = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"User/Applications/" error:nil];
        NSLog(@"appList = %@", appList);
        return YES;
    }
    NSLog(@"The device is NOT jail broken!");
    return NO;
}

#pragma mark 4.根据使用stat方法来判断cydia是否存在来判断,这个方法的思路还是通过判定cydia应用，但方法是使用stat函数，同时会判断是否有注入动态库。
+(BOOL)isJailBreak4
{
    struct stat stat_info;
    if (0 == stat("/Applications/Cydia.app", &stat_info)) {
        NSLog(@"Device is jailbroken");
        return YES;
    }
    
    return NO;
}


#pragma mark 5.攻击者可能会利用 Fishhook原理 hook了stat。那么，你可以看看stat是不是出自系统库，有没有被攻击者换掉：
+(BOOL)isJailBreak5
{
    int ret ;
    Dl_info dylib_info;
    int (*func_stat)(const char *, struct stat *) = stat;
    if ((ret = dladdr(func_stat, &dylib_info))) {
        NSLog(@"lib :%s", dylib_info.dli_fname);
        return YES;
    }
    return NO;
}

#pragma mark 6.读取环境变量这个DYLD_INSERT_LIBRARIES环境变量，在非越狱的机器上应该是空，越狱的机器上基本都会有Library/MobileSubstrate/MobileSubstrate.dylib
+(BOOL)isJailBreak6{
    if (printEnv()) {
        NSLog(@"The device is jail broken!");
        return YES;
    }
    NSLog(@"The device is NOT jail broken!");
    return NO;
}

@end
